package com.lizhen.core.function.commonscollections4;

import org.apache.commons.collections4.*;
import org.apache.commons.collections4.bag.HashBag;
import org.apache.commons.collections4.bidimap.TreeBidiMap;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.commons.collections4.map.LinkedMap;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

/**
 * @author lizhen
 */
public class CommonsCollections4 {

    /**
     * @author lizhen
     */
    public CommonsCollections4() {
    }

    static List<String> getList() {
        return null;
    }

    static boolean checkNotEmpty1(List<String> list) {
        return !(list == null || list.isEmpty());
    }

    static boolean checkNotEmpty2(List<String> list) {
        return CollectionUtils.isNotEmpty(list);
    }

    static boolean checkEmpty1(List<String> list) {
        return (list == null || list.isEmpty());
    }

    static boolean checkEmpty2(List<String> list) {
        return CollectionUtils.isEmpty(list);
    }

    /**
     * @author lizhen
     */
    public static void main(String[] args) {
        new CommonsCollections4().mUnion();
        new CommonsCollections4().mSubtract();
        new CommonsCollections4().mIntersection();
        new CommonsCollections4().mSubCollection();
        new CommonsCollections4().mEmpty();
        new CommonsCollections4().mNotEmpty();
        new CommonsCollections4().mFilterInverse();
        new CommonsCollections4().mFilter();
        new CommonsCollections4().mCollect();
        new CommonsCollections4().mCollate();
        new CommonsCollections4().mIgnoreNull();
        new CommonsCollections4().mHashBag();
        new CommonsCollections4().mBidiMap();
        new CommonsCollections4().mMapIterator();
        new CommonsCollections4().mOrderedMap();
    }

    /**
     * @author lizhen
     */
    private void mUnion() {
        List<String> list1 = Arrays.asList("A", "A", "A", "C", "B", "B");
        List<String> list2 = Arrays.asList("A", "A", "B", "B");

        System.out.println("List 1: " + list1);
        System.out.println("List 2: " + list2);
        System.out.println("Union of List 1 and List 2: " + CollectionUtils.union(list1, list2));
    }

    /**
     * @author lizhen
     */
    private void mSubtract() {
        List<String> list1 = Arrays.asList("A", "A", "A", "C", "B", "B");
        List<String> list2 = Arrays.asList("A", "A", "B", "B");

        System.out.println("List 1: " + list1);
        System.out.println("List 2: " + list2);
        System.out.println("List 1 - List 2: " + CollectionUtils.subtract(list1, list2));
    }

    /**
     * @author lizhen
     */
    private void mIntersection() {
        List<String> list1 = Arrays.asList("A", "A", "A", "C", "B", "B");
        List<String> list2 = Arrays.asList("A", "A", "B", "B");

        System.out.println("List 1: " + list1);
        System.out.println("List 2: " + list2);
        System.out.println("Commons Objects of List 1 and List 2: " + CollectionUtils.intersection(list1, list2));
    }

    /**
     * @author lizhen
     */
    private void mSubCollection() {
        List<String> list1 = Arrays.asList("A", "A", "A", "C", "B", "B");
        List<String> list2 = Arrays.asList("A", "A", "B", "B");

        System.out.println("List 1: " + list1);
        System.out.println("List 2: " + list2);
        System.out.println("Is List 2 contained in List 1: " + CollectionUtils.isSubCollection(list2, list1));
    }

    /**
     * @author lizhen
     */
    private void mEmpty() {
        List<String> list = getList();

        System.out.println("Empty List Check: " + checkEmpty1(list));
        System.out.println("Empty List Check: " + checkEmpty2(list));
    }

    /**
     * @author lizhen
     */
    private void mNotEmpty() {
        List<String> list = getList();

        System.out.println("Non-Empty List Check: " + checkNotEmpty1(list));
        System.out.println("Non-Empty List Check: " + checkNotEmpty2(list));
    }

    /**
     * @author lizhen
     */
    private void mFilterInverse() {
        List<Integer> integerList = new ArrayList<Integer>();
        integerList.addAll(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));

        System.out.println("Original List: " + integerList);

        CollectionUtils.filterInverse(integerList, new Predicate<Integer>() {
            @Override
            public boolean evaluate(Integer input) {
                if (input.intValue() % 2 == 0) {
                    return true;
                }
                return false;
            }
        });

        System.out.println("Filtered List (Odd numbers): " + integerList);
    }

    /**
     * @author lizhen
     */
    private void mFilter() {
        List<Integer> integerList = new ArrayList<Integer>();
        integerList.addAll(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8));

        System.out.println("Original List: " + integerList);

        CollectionUtils.filter(integerList, new Predicate<Integer>() {
            @Override
            public boolean evaluate(Integer input) {
                if (input.intValue() % 2 == 0) {
                    return true;
                }
                return false;
            }
        });

        System.out.println("Filtered List (Even numbers): " + integerList);
    }

    /**
     * @author lizhen
     */
    private void mCollect() {
        List<String> stringList = Arrays.asList("1", "2", "3");
        List<Integer> integerList = (List<Integer>) CollectionUtils.collect(stringList,
                new Transformer<String, Integer>() {
                    @Override
                    public Integer transform(String input) {
                        return Integer.parseInt(input);
                    }
                });

        System.out.println(integerList);
    }

    /**
     * @author lizhen
     */
    private void mCollate() {
        List<String> sortedList1 = Arrays.asList("A", "C", "E");
        List<String> sortedList2 = Arrays.asList("B", "D", "F");
        List<String> mergedList = CollectionUtils.collate(sortedList1, sortedList2);

        System.out.println(mergedList);
    }

    /**
     * @author lizhen
     */
    private void mIgnoreNull() {
        List<String> list = new LinkedList<String>();
        CollectionUtils.addIgnoreNull(list, null);
        CollectionUtils.addIgnoreNull(list, "a");

        System.out.println(list);
        if (list.contains(null)) {
            System.out.println("Null value is present");
        } else {
            System.out.println("Null value is not present");
        }
    }

    private void mHashBag() {
        Bag<String> bag = new HashBag<>();
        // add "a" two times to the bag.
        bag.add("a", 2);
        // add "b" one time to the bag.
        bag.add("b");
        // add "c" one time to the bag.
        bag.add("c");
        // add "d" three times to the bag.
        bag.add("d", 3);

        // get the count of "d" present in bag.
        System.out.println("d is present " + bag.getCount("d") + " times.");
        System.out.println("bag: " + bag);
        // get the set of unique values from the bag
        System.out.println("Unique Set: " + bag.uniqueSet());

        // remove 2 occurrences of "d" from the bag
        bag.remove("d", 2);

        System.out.println("2 occurences of d removed from bag: " + bag);
        System.out.println("d is present " + bag.getCount("d") + " times.");
        System.out.println("bag: " + bag);
        System.out.println("Unique Set: " + bag.uniqueSet());
    }

    private void mBidiMap() {
        BidiMap<String, String> bidi = new TreeBidiMap<>();
        bidi.put("One", "1");
        bidi.put("Two", "2");
        bidi.put("Three", "3");

        System.out.println(bidi.get("One"));
        System.out.println(bidi.getKey("1"));
        System.out.println("Original Map: " + bidi);

        bidi.removeValue("1");

        System.out.println("Modified Map: " + bidi);

        BidiMap<String, String> inversedMap = bidi.inverseBidiMap();

        System.out.println("Inversed Map: " + inversedMap);
    }

    private void mMapIterator() {
        IterableMap<String, String> map = new HashedMap<>();
        map.put("1", "One");
        map.put("2", "Two");
        map.put("3", "Three");
        map.put("4", "Four");
        map.put("5", "Five");
        MapIterator<String, String> iterator = map.mapIterator();

        while (iterator.hasNext()) {
            Object key = iterator.next();
            Object value = iterator.getValue();

            System.out.println("key: " + key);
            System.out.println("Value: " + value);

            iterator.setValue(value + "_");
        }
        System.out.println(map);
    }

    private void mOrderedMap() {
        OrderedMap<String, String> map = new LinkedMap<String, String>();
        map.put("One", "1");
        map.put("Two", "2");
        map.put("Three", "3");

        System.out.println(map.firstKey());
        System.out.println(map.nextKey("One"));
        System.out.println(map.nextKey("Two"));
    }
}
